#include "h_cc2640r2f_pwm_simple.h"

#include "h_cc2640r2f_define.h"

#if LOCK_PWM_HARDWARE_MODE

#include <ti/drivers/PWM.h>
#include <ti/drivers/pwm/PWMTimerCC26XX.h>

#if defined(ZCS_BOARD)
#include "../../simple_peropheral_board/zcs_board_defines.h"
#else
#include "board.h"
#endif

#else
#include <stdio.h>

#include "h_cc2640r2f_gpio.h"

#include <ti/sysbios/knl/Clock.h>

static Clock_Handle s_pwm_clockHandle = NULL;

#define S_PWM_SOFT_MODE_PWM_0_IO            AUTO_PLANT_BUZZER_PWM_IO

#define S_PWM_BASE_PERIOD                   50000
#endif

#if LOCK_PWM_HARDWARE_MODE

static unsigned char pwm_handle_nums = 0U;
// static PWM_Handle *H_CC2640R2F_PWMHandles = NULL;
static PWM_Handle H_CC2640R2F_PWMHandles[3];

signed char H_CC2640R2F_PWM_Init_MaxNums(unsigned char pwm_max_nums, unsigned short basic_freq)
{
    PWM_Params H_CC2640R2F_PWMparams;
    PWM_init();
    
    if(pwm_max_nums >= CC2640R2_LAUNCHXL_PWMCOUNT)
    {
        return (-2);
    }

    H_CC2640R2F_PWMparams.periodUnits = PWM_PERIOD_HZ;
    H_CC2640R2F_PWMparams.periodValue = basic_freq;
    H_CC2640R2F_PWMparams.dutyUnits = PWM_DUTY_FRACTION;
    H_CC2640R2F_PWMparams.dutyValue = PWM_DUTY_FRACTION_MAX / 2;
    H_CC2640R2F_PWMparams.idleLevel = PWM_IDLE_LOW;
    H_CC2640R2F_PWMparams.custom = NULL;

    // H_CC2640R2F_PWMHandles = (PWM_Handle *)H_CC2640R2F_DEBUG_MALLOC(sizeof(PWM_Handle) * pwm_max_nums);

    // if(NULL == H_CC2640R2F_PWMHandles)
    // {
    //     return (-1);
    // }

    for(pwm_handle_nums = 0; pwm_handle_nums < pwm_max_nums; pwm_handle_nums++)
    {
        H_CC2640R2F_PWMHandles[pwm_handle_nums] = PWM_open(pwm_handle_nums, \
                                                               &H_CC2640R2F_PWMparams);
        if(NULL == H_CC2640R2F_PWMHandles[pwm_handle_nums])
        {
            pwm_handle_nums = 0U;
            return (-3);
        }
    }

    pwm_handle_nums = pwm_max_nums - 1;

    return 0;
}

signed char H_CC2640R2F_PWM_ChannelSet_Per_ByIndex(unsigned char index, unsigned short per)
{
    if(index > pwm_handle_nums)
    {
        return (-1);
    }
    return PWM_setPeriod(H_CC2640R2F_PWMHandles[index], per);
}

signed char H_CC2640R2F_PWM_StartChannel_ByIndex(unsigned char index)
{
    if(index > pwm_handle_nums)
    {
        return (-1);
    }
    PWM_start(H_CC2640R2F_PWMHandles[index]);
    return 0;
}

signed char H_CC2640R2F_PWM_StopChannel_ByIndex(unsigned char index)
{
    if(index > pwm_handle_nums)
    {
        return (-1);
    }
    PWM_stop(H_CC2640R2F_PWMHandles[index]);
    return 0;
}

signed char H_CC2640R2F_PWM_SetDuty_ByIndex(unsigned char index, unsigned int persent)
{
    unsigned int real_duty = 0U;

    if(index > pwm_handle_nums)
    {
        return (-1);
    }

    if(persent < 0)
    {
        persent = 0;
    }
    else if(persent > 100)
    {
        persent = 100;
    }

    real_duty = (PWM_DUTY_FRACTION_MAX / 100) * persent;

    return PWM_setDuty(H_CC2640R2F_PWMHandles[index], real_duty);
}
//
//void H_CC2640R2F_PWM_StopChannel(void)
//{
//    PWM_stop(H_CC2640R2F_PWMHandle0);
//}
//static PWM_Handle H_CC2640R2F_PWMHandle0 = NULL;
//
//signed char H_CC2640R2F_PWM_Init_ByNum(unsigned char pwm_num, unsigned short freq)
//{
//    PWM_Params H_CC2640R2F_PWMparams;
//
//    PWM_init();
//    PWM_Params_init(&H_CC2640R2F_PWMparams);
//
//    H_CC2640R2F_PWMparams.periodUnits = PWM_PERIOD_HZ;
//    H_CC2640R2F_PWMparams.periodValue = freq;
//    H_CC2640R2F_PWMparams.dutyUnits = PWM_DUTY_FRACTION;
//    H_CC2640R2F_PWMparams.dutyValue = PWM_DUTY_FRACTION_MAX / 2;
//    H_CC2640R2F_PWMparams.idleLevel = PWM_IDLE_LOW;
//    H_CC2640R2F_PWMparams.custom = NULL;
//
//
//    switch(pwm_num)
//    {
//        case 0:
//            H_CC2640R2F_PWMHandle0 = PWM_open(CC2640R2_LAUNCHXL_PWM0, \
//                                        &H_CC2640R2F_PWMparams);
//            break;
//        case 1:
//            H_CC2640R2F_PWMHandle0 = PWM_open(CC2640R2_LAUNCHXL_PWM1, \
//                                        &H_CC2640R2F_PWMparams);
//            break;
//        case 2:
//            H_CC2640R2F_PWMHandle0 = PWM_open(CC2640R2_LAUNCHXL_PWM2, \
//                                        &H_CC2640R2F_PWMparams);
//            break;
//        default:
//            break;
//    }
//
//    if(H_CC2640R2F_PWMHandle0 == NULL)
//    {
//        return (-1);
//    }
//
//    return 0;
//}
//
//void H_CC2640R2F_PWM_StartChannel(void)
//{
//    PWM_start(H_CC2640R2F_PWMHandle0);
//}
//
//void H_CC2640R2F_PWM_StopChannel(void)
//{
//    PWM_stop(H_CC2640R2F_PWMHandle0);
//}
//
//
//signed char H_CC2640R2F_PWM_ChannelSet_Per(unsigned short per)
//{
//    return PWM_setPeriod(H_CC2640R2F_PWMHandle0, per);
//}

#else
static unsigned char s_soft_pwm_run_num = 0;
#define S_PWM_MAX_COUNT                         10
static unsigned short s_soft_pwm_run_count_times = 0;
static unsigned short s_soft_pwm_run_duty = 5;

static void s_pwm_callback(UArg arg0)
{
    if(s_soft_pwm_run_count_times >= S_PWM_MAX_COUNT)
    {
        s_soft_pwm_run_count_times = 0;
    }
    else
    {
        s_soft_pwm_run_count_times++;
    }

    if(s_soft_pwm_run_count_times <= s_soft_pwm_run_duty)
    {
        switch(s_soft_pwm_run_num)
        {
            case 0:
                H_CC2640R2F_GPIO_OutputSet(S_PWM_SOFT_MODE_PWM_0_IO, 1);
                break;
            case 1:
                H_CC2640R2F_GPIO_OutputSet(AUTO_PLANT_A_PWM_IO, 1);
                break;
            case 2:
                H_CC2640R2F_GPIO_OutputSet(AUTO_PLANT_B_PWM_IO, 1);
                break;
            default:
                break;
        }
    }
    else
    {
        switch(s_soft_pwm_run_num)
        {
            case 0:
                H_CC2640R2F_GPIO_OutputSet(S_PWM_SOFT_MODE_PWM_0_IO, 0);
                break;
            case 1:
                H_CC2640R2F_GPIO_OutputSet(AUTO_PLANT_A_PWM_IO, 0);
                break;
            case 2:
                H_CC2640R2F_GPIO_OutputSet(AUTO_PLANT_B_PWM_IO, 0);
                break;
            default:
                break;
        }
    }

    // printf("call back\r\n");
    // if(s_pwm_clockHandle != NULL)
    // {
    //     switch(s_soft_pwm_run_num)
    //     {
    //         case 0:
    //             H_CC2640R2F_GPIO_OutputToggle(S_PWM_SOFT_MODE_PWM_0_IO);
    //             break;
    //         case 1:
    //             H_CC2640R2F_GPIO_OutputToggle(AUTO_PLANT_A_PWM_IO);
    //             break;
    //         case 2:
    //             H_CC2640R2F_GPIO_OutputToggle(AUTO_PLANT_B_PWM_IO);
    //             break;
    //         default:
    //             break;
    //     }
        
    // }
}

signed char H_CC2640R2F_PWM_Init_ByNum(unsigned char pwm_num, unsigned short freq)
{
    unsigned int timeperiod = S_PWM_BASE_PERIOD / freq;
    timeperiod *= S_PWM_MAX_COUNT;

    Clock_Params params;
    Clock_Params_init(&params);

    params.period = timeperiod;//timeoutTick;
    params.startFlag = 0;   //Do not start immediately

    s_pwm_clockHandle = Clock_create(s_pwm_callback, \
                                             1000, &params, NULL);

    s_soft_pwm_run_num = pwm_num;

    if(NULL == s_pwm_clockHandle)
    {
        // printf("s_pwm_callback init failed\r\n");
        return (-1);
    }
    // printf("s_pwm_callback init success\r\n");
    return 0;
}

void H_CC2640R2F_PWM_StartChannel(void)
{
    if(NULL != s_pwm_clockHandle)
    {
        Clock_start(s_pwm_clockHandle);
    }
}

void H_CC2640R2F_PWM_StopChannel(void)
{
    if(NULL != s_pwm_clockHandle)
    {
        // H_CC2640R2F_GPIO_OutputSet(S_PWM_SOFT_MODE_PWM_0_IO, 0);
        switch(s_soft_pwm_run_num)
        {
            case 0:
                H_CC2640R2F_GPIO_OutputSet(S_PWM_SOFT_MODE_PWM_0_IO, 0);
                break;
            case 1:
                H_CC2640R2F_GPIO_OutputSet(AUTO_PLANT_A_PWM_IO, 0);
                break;
            case 2:
                H_CC2640R2F_GPIO_OutputSet(AUTO_PLANT_B_PWM_IO, 0);
                break;
            default:
                break;
        }
        Clock_stop(s_pwm_clockHandle);
    }
}


signed char H_CC2640R2F_PWM_ChannelSet_Per(unsigned short per)
{
    if(NULL != s_pwm_clockHandle)
    {
        per *= S_PWM_MAX_COUNT;
        Clock_setPeriod(s_pwm_clockHandle, S_PWM_BASE_PERIOD / per);
    }
    return 0;
}

signed char H_CC2640R2F_PWM_ChannelSet_Duty_Persent(unsigned short duty)
{
    if(NULL != s_pwm_clockHandle)
    {
        s_soft_pwm_run_duty = duty / S_PWM_MAX_COUNT;
        // Clock_setPeriod(s_pwm_clockHandle, S_PWM_BASE_PERIOD / per);
    }
    return 0;
}

#endif

